{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "238fc475",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "matchIdx: (0, 4) matchValue: 0.9056315422058105\n",
      "matchIdx: (0, 0) matchValue: 0.8855833411216736\n",
      "matchIdx: (0, 2) matchValue: 0.9056539535522461\n",
      "matchIdx: (0, 0) matchValue: 0.8855833411216736\n",
      "matchIdx: (0, 3) matchValue: 0.9215268492698669\n",
      "matchIdx: (0, 4) matchValue: 0.9056315422058105\n",
      "matchIdx: (0, 0) matchValue: 0.8855833411216736\n",
      "matchIdx: (0, 0) matchValue: 0.8855833411216736\n",
      "matchIdx: (0, 0) matchValue: 0.8855833411216736\n",
      "matchIdx: (0, 2) matchValue: 0.9056539535522461\n",
      "matchIdx: (0, 3) matchValue: 0.9215268492698669\n",
      "matchIdx: (0, 4) matchValue: 0.9056315422058105\n",
      "matchIdx: (0, 5) matchValue: 0.8958724141120911\n",
      "matchIdx: (0, 6) matchValue: 0.9112050533294678\n",
      "matchIdx: (0, 7) matchValue: 0.9345963001251221\n",
      "matchIdx: (0, 8) matchValue: 0.8973314762115479\n",
      "card number:  4020340002345678\n"
     ]
    }
   ],
   "source": [
    "#extract the regoin of all numbers\n",
    "import cv2 as cv\n",
    "import numpy as np\n",
    "from operator import itemgetter\n",
    "\n",
    "creditCard = cv.imread(\"../data/creditCard/credit_card_02.png\")\n",
    "cv.imshow(\"creditCard\", creditCard)\n",
    "\n",
    "CCGray = cv.cvtColor(creditCard, cv.COLOR_BGR2GRAY)\n",
    "\n",
    "# PREPROCESS: all possible single number rects\n",
    "ret, CCBinary = cv.threshold(CCGray, 160, 255, 0)\n",
    "\n",
    "# dKernel = np.ones((3,3), np.uint8)\n",
    "dKernel = np.array([[0,0,0],[1,1,1],[0,0,0]], np.uint8)\n",
    "# CCBinary_dilate = cv.dilate(CCBinary, dKernel, iterations = 1)\n",
    "\n",
    "dKernel2 = np.ones((3,3), np.uint8)\n",
    "CCBinary_dilate = cv.morphologyEx(CCBinary, cv.MORPH_CLOSE, dKernel2)\n",
    "CCBinary_dilate_cpy = CCBinary_dilate.copy()\n",
    "cv.imshow(\"CCBinary_dilate_cpy\", CCBinary_dilate_cpy)\n",
    "cv.waitKey(0)\n",
    "\n",
    "# FIND: all possible single number rects\n",
    "retrievalMode = cv.RETR_LIST\n",
    "approxMethod = cv.CHAIN_APPROX_NONE\n",
    "contours, hierachy = cv.findContours(CCBinary_dilate, retrievalMode, approxMethod)\n",
    "\n",
    "# cv.drawContours(creditCard, contours, -1, (0,0,255), 1)\n",
    "\n",
    "# SELECT: all possible single number rects acoording to prop(h/w) from 1.2~2\n",
    "bbox = []\n",
    "for cnt in contours:\n",
    "    x,y,w,h = cv.boundingRect(cnt)\n",
    "    prop = h*1./w\n",
    "    if prop > 1.5 - 0.3 and prop < 1.5 + 0.5:\n",
    "        bbox.append((x,y,w,h))\n",
    "\n",
    "for (x,y,w,h) in bbox:    \n",
    "    cv.rectangle(CCBinary_dilate, (x,y), (x+w,y+h), 255, 1)\n",
    "\n",
    "draw0 = np.zeros(CCBinary_dilate.shape, np.uint8)\n",
    "for (x,y,w,h) in bbox:    \n",
    "    cv.rectangle(draw0, (x,y), (x+w,y+h), 255, 1)\n",
    "\n",
    "CCBinary_dilate2 = cv.dilate(CCBinary_dilate, dKernel, iterations = 6)\n",
    "\n",
    "retrievalMode = cv.RETR_LIST\n",
    "approxMethod = cv.CHAIN_APPROX_NONE\n",
    "contours, hierachy = cv.findContours(CCBinary_dilate2, retrievalMode, approxMethod)\n",
    "\n",
    "# SELECT: all possible multi-number rects acoording to prop(w/h) from 3~5\n",
    "bbox2 = []\n",
    "draw1 = np.zeros(CCBinary_dilate.shape, np.uint8)\n",
    "for cnt in contours:\n",
    "    x,y,w,h = cv.boundingRect(cnt)\n",
    "    prop = w*1./h\n",
    "    if prop > 3 and prop < 5:\n",
    "        bbox2.append((x,y,w,h))\n",
    "        cv.rectangle(draw1, (x,y), (x+w,y+h), 255, 1)\n",
    "\n",
    "# SELECT: 4 multi-number rects\n",
    "bbox2.sort(key=itemgetter(0,1))\n",
    "# print(bbox2)\n",
    "\n",
    "def righttopLessThanNextLefttop(lst):\n",
    "    for idx, (x,y,w,h) in enumerate(lst):\n",
    "        if idx == len(lst) - 1:\n",
    "            break\n",
    "        if lst[idx][0] + lst[idx][2] >= lst[idx+1][0]:\n",
    "            return False\n",
    "    \n",
    "    return True\n",
    "\n",
    "bbox3 = []\n",
    "realTarget = []\n",
    "draw2 = np.zeros(CCBinary_dilate.shape, np.uint8)\n",
    "for idx, (x,y,w,h) in enumerate(bbox2):\n",
    "    length = len(bbox2)\n",
    "    \n",
    "    limitY = 10\n",
    "    ref = bbox2[idx]\n",
    "    target = [ref]\n",
    "    for remain_idx in range(idx+1,length):\n",
    "        if abs(ref[1] - bbox2[remain_idx][1]) <= limitY:\n",
    "            target.append(bbox2[remain_idx])\n",
    "            if len(target) >= 4 and righttopLessThanNextLefttop(target):\n",
    "                realTarget = target\n",
    "                break\n",
    "\n",
    "# for  idx, (x,y,w,h) in enumerate(realTarget):\n",
    "#     cv.rectangle(draw2, (x,y), (x+w,y+h), 255, 1)\n",
    "#     cv.imshow(\"draw2\", draw2)\n",
    "#     cv.waitKey(0)\n",
    "            \n",
    "\n",
    "# EXTRACT: 4 multi-number ROI Img\n",
    "ROIs = []\n",
    "for  idx, (x,y,w,h) in enumerate(realTarget):\n",
    "    ROIs.append(CCBinary_dilate_cpy[y:y+h, x:x+w].copy())\n",
    "\n",
    "# FIND: all single number ROI\n",
    "#[another method: sort single num rect via X and \n",
    "#select single num rect is in the 4 multi-number rect]\n",
    "\n",
    "def getCardNumberImg(roi_binary):\n",
    "    retrievalMode = cv.RETR_EXTERNAL\n",
    "    approxMethod = cv.CHAIN_APPROX_NONE\n",
    "    contours, hierachy = cv.findContours(roi_binary, retrievalMode, approxMethod)\n",
    "\n",
    "    bbox = []\n",
    "    for cnt in contours:\n",
    "        x,y,w,h = cv.boundingRect(cnt)\n",
    "        bbox.insert(0, (x,y,w,h))\n",
    "    bbox.sort(key=itemgetter(0)) \n",
    "    \n",
    "    numberArray = []\n",
    "    for x,y,w,h in bbox:\n",
    "        numAlone = roi_binary[y:y+h, x:x+w].copy()\n",
    "        res = cv.resize(numAlone,(60, 90), interpolation = cv.INTER_CUBIC)\n",
    "#         numberArray.insert(0,res)\n",
    "        numberArray.append(res)\n",
    "    \n",
    "    return numberArray\n",
    "\n",
    "AllSingleNumImg = []\n",
    "for  roi in ROIs:\n",
    "    AllSingleNumImg = AllSingleNumImg + getCardNumberImg(roi)\n",
    "    \n",
    "# find: \n",
    "def putTextAboveNumber(img, text, textBottomLeftPt):\n",
    "    fontType = cv.FONT_HERSHEY_SIMPLEX\n",
    "    fontScale = 1\n",
    "    color   = (0,0,255)\n",
    "    thinknessPx = 1\n",
    "    lineType = cv.LINE_AA\n",
    "    cv.putText(img, text,textBottomLeftPt, \n",
    "               fontType,fontScale, color,thinknessPx,lineType)\n",
    "\n",
    "def numRefArray():\n",
    "    ref = cv.imread(\"../data/creditCard/ocr_a_reference.png\")\n",
    "    refGray = cv.cvtColor(ref, cv.COLOR_BGR2GRAY)\n",
    "\n",
    "    ret, CCBinary = cv.threshold(refGray, 160, 255, 1)\n",
    "#     cv.imshow(\"CCBinary\", CCBinary)\n",
    "#     cv.waitKey(0)\n",
    "\n",
    "    retrievalMode = cv.RETR_EXTERNAL\n",
    "    approxMethod = cv.CHAIN_APPROX_NONE\n",
    "    contours, hierachy = cv.findContours(CCBinary, retrievalMode, approxMethod)\n",
    "\n",
    "    bbox = []\n",
    "    numberRefArray = []\n",
    "\n",
    "    for cnt in contours:\n",
    "        x,y,w,h = cv.boundingRect(cnt)\n",
    "        bbox.insert(0, (x,y,w,h))\n",
    "        numAlone = CCBinary[y:y+h, x:x+w].copy()\n",
    "        res = cv.resize(numAlone,(60, 90), interpolation = cv.INTER_CUBIC)\n",
    "#         print(res.shape)\n",
    "        numberRefArray.insert(0,res)\n",
    "\n",
    "    return numberRefArray\n",
    "\n",
    "numberStr = [\"0\",\"1\",\"2\",\"3\",\"4\",\n",
    "             \"5\",\"6\",\"7\",\"8\",\"9\"]\n",
    "cardNumber = \"\"\n",
    "numRef = numRefArray()\n",
    "for  numImg in AllSingleNumImg:   \n",
    "    matchArray = []\n",
    "    for idx,numberRef in enumerate(numRef):\n",
    "        res = cv.matchTemplate(numImg, numberRef, cv.TM_CCOEFF_NORMED)\n",
    "        matchArray.append(res)\n",
    "        \n",
    "    minV,maxV, minL,maxL = cv.minMaxLoc(np.array(matchArray))\n",
    "    print('matchIdx:', maxL, 'matchValue:', maxV)\n",
    "    \n",
    "    idx = maxL[1]\n",
    "    cardNumber += numberStr[idx]\n",
    "    \n",
    "#     cv.imshow(\"CNImgs\", numImg)\n",
    "#     cv.waitKey(0)\n",
    "\n",
    "print(\"card number: \", cardNumber)      \n",
    "# putTextAboveNumber(creditCard, cardNumber, (realTarget[0][0],realTarget[0][1]) )\n",
    "\n",
    "for idx, (x,y,w,h) in enumerate(realTarget):\n",
    "    cardNumStartIdx = idx*4\n",
    "    putTextAboveNumber(creditCard, cardNumber[cardNumStartIdx:cardNumStartIdx+4], (x,y) )\n",
    "    \n",
    "\n",
    "cv.imshow(\"creditCard\", creditCard)\n",
    "# cv.imshow(\"CCGray\", CCGray)\n",
    "# cv.imshow(\"CCBinary\", CCBinary)\n",
    "# cv.imshow(\"CCBinary_dilate\", CCBinary_dilate)\n",
    "cv.imshow(\"draw0\", draw0)\n",
    "# cv.imshow(\"CCBinary_dilate2\", CCBinary_dilate2)\n",
    "# cv.imshow(\"draw1\", draw1)\n",
    "\n",
    "cv.waitKey(0)\n",
    "cv.destroyAllWindows()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a35d1803",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "c824e087",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(90, 60)\n",
      "(90, 60)\n",
      "(90, 60)\n",
      "(90, 60)\n",
      "(90, 60)\n",
      "(90, 60)\n",
      "(90, 60)\n",
      "(90, 60)\n",
      "(90, 60)\n",
      "(90, 60)\n",
      "matchIdx: (0, 4) matchValue: 0.8594766855239868\n",
      "matchIdx: (0, 0) matchValue: 0.9017449021339417\n",
      "matchIdx: (0, 0) matchValue: 0.9017449021339417\n",
      "matchIdx: (0, 0) matchValue: 0.9017449021339417\n",
      "matchIdx: (0, 1) matchValue: 0.8864133954048157\n",
      "matchIdx: (0, 2) matchValue: 0.8636502623558044\n",
      "matchIdx: (0, 3) matchValue: 0.8692161440849304\n",
      "matchIdx: (0, 4) matchValue: 0.8594766855239868\n",
      "matchIdx: (0, 5) matchValue: 0.844538152217865\n",
      "matchIdx: (0, 6) matchValue: 0.8709545731544495\n",
      "matchIdx: (0, 7) matchValue: 0.9149667024612427\n",
      "matchIdx: (0, 8) matchValue: 0.8718718886375427\n",
      "matchIdx: (0, 9) matchValue: 0.8892417550086975\n",
      "matchIdx: (0, 0) matchValue: 0.9017449021339417\n",
      "matchIdx: (0, 1) matchValue: 0.8894174098968506\n",
      "matchIdx: (0, 0) matchValue: 0.9017449021339417\n"
     ]
    }
   ],
   "source": [
    "#extract the all numbers\n",
    "import cv2 as cv\n",
    "import numpy as np\n",
    "\n",
    "def getCardNumberImg():\n",
    "    cardNum = cv.imread(\"../data/creditCard/tmp/card.png\")\n",
    "    cardNumGray = cv.cvtColor(cardNum, cv.COLOR_BGR2GRAY)\n",
    "\n",
    "    ret, CNBinary = cv.threshold(cardNumGray, 160, 255, 0)\n",
    "    cv.imshow(\"CNBinary\", CNBinary)\n",
    "    cv.waitKey(0)\n",
    "\n",
    "    retrievalMode = cv.RETR_EXTERNAL\n",
    "    approxMethod = cv.CHAIN_APPROX_NONE\n",
    "    contours, hierachy = cv.findContours(CNBinary, retrievalMode, approxMethod)\n",
    "\n",
    "    bbox = []\n",
    "    numberRefArray = []\n",
    "\n",
    "    for cnt in contours:\n",
    "        x,y,w,h = cv.boundingRect(cnt)\n",
    "        bbox.insert(0, (x,y,w,h))\n",
    "        numAlone = CNBinary[y:y+h, x:x+w].copy()\n",
    "        res = cv.resize(numAlone,(60, 90), interpolation = cv.INTER_CUBIC)\n",
    "        numberRefArray.insert(0,res)\n",
    "    \n",
    "    return numberRefArray\n",
    "\n",
    "ref = cv.imread(\"../data/creditCard/ocr_a_reference.png\")\n",
    "refGray = cv.cvtColor(ref, cv.COLOR_BGR2GRAY)\n",
    "\n",
    "ret, CCBinary = cv.threshold(refGray, 160, 255, 1)\n",
    "cv.imshow(\"CCBinary\", CCBinary)\n",
    "cv.waitKey(0)\n",
    "\n",
    "retrievalMode = cv.RETR_EXTERNAL\n",
    "approxMethod = cv.CHAIN_APPROX_NONE\n",
    "contours, hierachy = cv.findContours(CCBinary, retrievalMode, approxMethod)\n",
    "\n",
    "bbox = []\n",
    "numberRefArray = []\n",
    "\n",
    "for cnt in contours:\n",
    "    x,y,w,h = cv.boundingRect(cnt)\n",
    "    bbox.insert(0, (x,y,w,h))\n",
    "    numAlone = CCBinary[y:y+h, x:x+w].copy()\n",
    "    res = cv.resize(numAlone,(60, 90), interpolation = cv.INTER_CUBIC)\n",
    "    print(res.shape)\n",
    "    numberRefArray.insert(0,res)\n",
    "#     cv.rectangle(ref, (x,y), (x+w,y+h), (0,0,255), 1)\n",
    "#     cv.imshow(\"numAlone\", res)\n",
    "#     cv.waitKey(0)\n",
    "\n",
    "CNImgs = getCardNumberImg()\n",
    "\n",
    "for cni in CNImgs:\n",
    "    cv.imshow(\"cni\", cni)\n",
    "    cv.waitKey(0)\n",
    "    matchArray = []\n",
    "    for idx,numberRef in enumerate(numberRefArray):\n",
    "        res = cv.matchTemplate(cni, numberRef, cv.TM_CCOEFF_NORMED)\n",
    "        matchArray.append(res)\n",
    "#         print(idx, ':', res)\n",
    "        \n",
    "    minV,maxV, minL,maxL = cv.minMaxLoc(np.array(matchArray))\n",
    "    print('matchIdx:', maxL, 'matchValue:', maxV)\n",
    "    \n",
    "    cv.imshow(\"CNImgs\", cni)\n",
    "    cv.waitKey(0)\n",
    "#     break\n",
    "\n",
    "cv.destroyAllWindows()\n",
    "#     bbox\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "4877f451",
   "metadata": {},
   "outputs": [],
   "source": [
    "#extract the all numbers in ROI\n",
    "import cv2 as cv\n",
    "import numpy as np\n",
    "\n",
    "cardNum = cv.imread(\"../data/creditCard/tmp/card.png\")\n",
    "cardNumGray = cv.cvtColor(cardNum, cv.COLOR_BGR2GRAY)\n",
    "\n",
    "ret, CNBinary = cv.threshold(cardNumGray, 160, 255, 0)\n",
    "cv.imshow(\"CNBinary\", CNBinary)\n",
    "cv.waitKey(0)\n",
    "\n",
    "retrievalMode = cv.RETR_EXTERNAL\n",
    "approxMethod = cv.CHAIN_APPROX_NONE\n",
    "contours, hierachy = cv.findContours(CNBinary, retrievalMode, approxMethod)\n",
    "\n",
    "bbox = []\n",
    "numberRefArray = []\n",
    "\n",
    "for cnt in contours:\n",
    "    x,y,w,h = cv.boundingRect(cnt)\n",
    "    bbox.insert(0, (x,y,w,h))\n",
    "    numAlone = CNBinary[y:y+h, x:x+w].copy()\n",
    "    res = cv.resize(numAlone,(60, 90), interpolation = cv.INTER_CUBIC)\n",
    "    numberRefArray.insert(0,res)\n",
    "    cv.imshow(\"numAlone\", res)\n",
    "    cv.waitKey(0)\n",
    "\n",
    "cv.destroyAllWindows()\n",
    "#     bbox"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "50c088b9",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
